package org.xxpay.pay.channel.ysepay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.xxpay.core.common.domain.api.AbstractRes;
import org.xxpay.core.common.domain.api.ApiBuilder;
import org.xxpay.core.common.domain.api.PayRes;
import org.xxpay.core.common.util.AmountUtil;
import org.xxpay.core.common.util.DateUtil;
import org.xxpay.core.common.util.MyLog;
import org.xxpay.core.common.vo.DBApplicationConfig;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.pay.channel.BasePayment;
import org.xxpay.pay.channel.ysepay.util.Https;
import org.xxpay.pay.channel.ysepay.util.SignUtils;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class YsepayPaymentService extends BasePayment {

    private static final MyLog logger = MyLog.getLog(YsepayPaymentService.class);

    @Override
    public String getChannelName() {
        return YsepayConfig.CHANNEL_NAME_YSEPAY;
    }

//    @Override
//    public String getOrderId(PayOrder payOrder){
//
//        SimpleDateFormat fm = new SimpleDateFormat("yyMMddHHmmss");
//        return String.format("%sR%04d", fm.format(new Date()), pay_seq.getAndIncrement() % 10000);
//
//    }

    @Override
    public AbstractRes pay(PayOrder payOrder) {

        AbstractRes retObj = null;
        String channelId = payOrder.getChannelId();
        switch (channelId) {
            case YsepayConfig.PAY_CHANNEL_YSEPAY_B2C : //网银支付
                retObj = this.doB2C(payOrder);
                break;
            case YsepayConfig.PAY_CHANNEL_YSEPAY_PC : //快捷支付：PC
                retObj = this.doPC(payOrder);
                break;
            case YsepayConfig.PAY_CHANNEL_YSEPAY_WAP : //快捷支付：wap
                retObj = this.doWAP(payOrder);
                break;
            case YsepayConfig.PAY_CHANNEL_YSEPAY_WXPAY_QR : //微信扫码支付
                retObj = this.doQR(payOrder, "1902000");
                break;
            case YsepayConfig.PAY_CHANNEL_YSEPAY_ALIPAY_QR : //支付宝扫码支付
                retObj = this.doQR(payOrder, "1903000");
                break;
            default: return ApiBuilder.bizError("不支持的银盛渠道[channelId="+channelId+"]");
        }

        return retObj;

    }

    /**
     * 网银支付
     * @param payOrder
     * @return
     */
    private AbstractRes doB2C(PayOrder payOrder){

        PayRes retObj = ApiBuilder.buildSuccess(PayRes.class);

        try {
            Date nowTime = new Date();  //获取当前的时间戳
            YsepayConfig ysepayConfig = new YsepayConfig(getPayParam(payOrder));  //银盛通道配置信息

            Map<String, String> reqParamMap = new HashMap<>();
            reqParamMap.put("method", "ysepay.online.directpay.createbyuser");	//接口名称：银盛收银台
            reqParamMap.put("partner_id", ysepayConfig.getSellerId()); //商户在银盛支付平台开设的用户号[商户号]
            reqParamMap.put("timestamp", DateUtil.date2Str(nowTime)); //发送请求的时间，格式"yyyy-MM-dd HH:mm:ss"
            reqParamMap.put("charset", YsepayConfig.CHARSET); //商户网站使用的编码格式
            reqParamMap.put("sign_type", "RSA"); //RSA
            DBApplicationConfig dbConfig = getDBApplicationConfig();
            reqParamMap.put("notify_url", super.getNotifyUrl(getChannelName(), dbConfig)); //异步通知地址
            reqParamMap.put("return_url", super.getReturnUrl(getChannelName(), dbConfig)); //页面跳转地址
            reqParamMap.put("version", "3.0"); //接口版本
            reqParamMap.put("tran_type", ""); //交易类型，说明：1或者空：即时到账，2：担保交易  可空
            reqParamMap.put("out_trade_no", payOrder.getPayOrderId()); //商户生成的订单号，生成规则前8位必须为交易日期，如20180525，范围跨度支持包含当天在内的前后一天，且只能由大小写英文字母、数字、下划线及横杠组成
            reqParamMap.put("shopdate", DateUtil.date2Str(nowTime, DateUtil.FORMAT_YYYY_MM_DD2)); //商户日期(该参数做交易与查询时需要一致) 该日期需在当日的前后一天时间范围之内
            reqParamMap.put("subject", payOrder.getSubject()); //商品的标题/交易标题/订单标题/订单关键字等。
            reqParamMap.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getAmount() + "")); //该笔订单的资金总额，单位为RMB-Yuan。
            reqParamMap.put("seller_id", ysepayConfig.getSellerId()); //收款方银盛支付用户号
            reqParamMap.put("seller_name", ysepayConfig.getSellerName()); //收款方银盛支付客户名
            reqParamMap.put("timeout_express", "2h"); //设置未付款交易的超时时间
            reqParamMap.put("business_code", ysepayConfig.getBusinessCode()); //业务代码

//            reqParamMap.put("pay_mode", ""); //直连银行信息,直联模式使用,锁定指定的支付方式，
//            reqParamMap.put("bank_type", ""); //直连银行信息,和paymode配合使用,若填写了则直接锁定该银行支付
//            reqParamMap.put("bank_account_type", ""); //直连银行信息,和paymode配合使用，付款方银行账户类型
//            reqParamMap.put("support_card_type", ""); //直连银行信息,和paymode配合使用,支持卡类型,
//            reqParamMap.put("mer_outside_custid", ""); //商户用户id
//            reqParamMap.put("bank_account_no", ""); //卡号，当pay_mode为fastpay或fdfastpay时必填
//            reqParamMap.put("fast_pay_name", ""); //姓名，当pay_mode为fastpay或fdfastpay时必填
//            reqParamMap.put("fast_pay_id_no", ""); //证件号，当pay_mode为fastpay或fdfastpay时必填
//            reqParamMap.put("fast_pay_validity", ""); //有效期，当pay_mode为fastpay或fdfastpay时，且卡类型为信用卡时必填
//            reqParamMap.put("fast_pay_mobile", ""); //手机号,当pay_mode为fastpay时使用
//            reqParamMap.put("fast_pay_cvv2", ""); //安全码,当pay_mode为fastpay或fdfastpay时，且卡类型为信用卡时必填
//            reqParamMap.put("extend_params", ""); //业务扩展参数，一个json字符串

            //reqParamMap.put("extra_common_param", ""); //公用回传参数
            //reqParamMap.put("sub_merchant", ""); //二级商户信息
            //reqParamMap.put("consignee_info", ""); //收货人信息json格式
            //reqParamMap.put("appid", ""); //微信分配的子商户公众号账号ID

            //证书文件
            String privatePfxFilePath = payConfig.getCertRootPath() + File.separator + getChannelName() + File.separator + ysepayConfig.getPrivatePfxPath();
            String signStr = SignUtils.rsaSign(reqParamMap, privatePfxFilePath, ysepayConfig.getPfxPwd());
            reqParamMap.put("sign", signStr); //RSA签名字符串，再用Base64编码

            //拼接form表单数据
            StringBuffer html = new StringBuffer("<form id='xxpay_ysepayForm' method='post' action='"+YsepayConfig.API_URL+"'>");
            reqParamMap.keySet().forEach(key -> html.append("<input type='hidden' name='"+key+"' value='"+reqParamMap.get(key)+"' />"));
            html.append("</form><script>document.getElementById('xxpay_ysepayForm').submit();</script>");

            retObj.setJumpInfo(html.toString());

            int result = commonService.payOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
            logger.info("[{}]更新订单状态为支付中:payOrderId={},prepayId={},result={}", getChannelName(), payOrder.getPayOrderId(), "", result);
            return retObj;

        } catch (Exception e) {
            logger.error("ysepay error", e);
            return ApiBuilder.bizError("下单失败");
        }
    }

    /**
     * 快捷：pc
     * @param payOrder
     * @return
     */
    private AbstractRes doPC(PayOrder payOrder){

        return doB2C(payOrder);  //银盛收银台， 默认支付方式为快捷支付

    }

    /**
     * 快捷：wap
     * @param payOrder
     * @return
     */
    private AbstractRes doWAP(PayOrder payOrder){

        return doB2C(payOrder);  //银盛收银台， 默认支付方式为快捷支付

    }

    /**
     * 扫码支付
     * @param payOrder
     * @param bankType 微信扫码支付:1902000  支付宝：1903000
     * @return
     */
    private AbstractRes doQR(PayOrder payOrder, String bankType){

        PayRes retObj = ApiBuilder.buildSuccess(PayRes.class);

        try {
            YsepayConfig ysepayConfig = new YsepayConfig(getPayParam(payOrder));
            Date nowTime = new Date();
            Map<String, String> reqParamMap = new HashMap<>();
            reqParamMap.put("method", "ysepay.online.qrcodepay");	//扫码支付
            reqParamMap.put("partner_id", ysepayConfig.getSellerId()); //商户在银盛支付平台开设的用户号[商户号]
            reqParamMap.put("timestamp", DateUtil.date2Str(nowTime)); //发送请求的时间，格式"yyyy-MM-dd HH:mm:ss"
            reqParamMap.put("charset", YsepayConfig.CHARSET); //商户网站使用的编码格式
            reqParamMap.put("sign_type", "RSA"); //RSA
            DBApplicationConfig dbConfig = getDBApplicationConfig();
            reqParamMap.put("notify_url", super.getNotifyUrl(getChannelName(), dbConfig)); //异步通知地址
            reqParamMap.put("return_url", super.getReturnUrl(getChannelName(), dbConfig)); //页面跳转地址
            reqParamMap.put("version", "3.0"); //接口版本
            reqParamMap.put("tran_type", ""); //交易类型，说明：1或者空：即时到账，2：担保交易  可空
            reqParamMap.put("out_trade_no", payOrder.getPayOrderId()); //商户生成的订单号，生成规则前8位必须为交易日期，如20180525，范围跨度支持包含当天在内的前后一天，且只能由大小写英文字母、数字、下划线及横杠组成
            reqParamMap.put("shopdate", DateUtil.date2Str(nowTime, DateUtil.FORMAT_YYYY_MM_DD2)); //商户日期(该参数做交易与查询时需要一致) 该日期需在当日的前后一天时间范围之内
            reqParamMap.put("subject", payOrder.getSubject()); //商品的标题/交易标题/订单标题/订单关键字等。
            reqParamMap.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getAmount() + "")); //该笔订单的资金总额，单位为RMB-Yuan。
            reqParamMap.put("seller_id", ysepayConfig.getSellerId()); //收款方银盛支付用户号
            reqParamMap.put("seller_name", ysepayConfig.getSellerName()); //收款方银盛支付客户名
            reqParamMap.put("timeout_express", "2h"); //设置未付款交易的超时时间
//            reqParamMap.put("pay_mode", ""); //直连银行信息,直联模式使用,锁定指定的支付方式，
//            reqParamMap.put("bank_type", "1903000"); //直连银行信息,和paymode配合使用,若填写了则直接锁定该银行支付
//            reqParamMap.put("bank_account_type", ""); //直连银行信息,和paymode配合使用，付款方银行账户类型
//            reqParamMap.put("support_card_type", ""); //直连银行信息,和paymode配合使用,支持卡类型,
//            reqParamMap.put("mer_outside_custid", ""); //商户用户id
//            reqParamMap.put("bank_account_no", ""); //卡号，当pay_mode为fastpay或fdfastpay时必填
//            reqParamMap.put("fast_pay_name", ""); //姓名，当pay_mode为fastpay或fdfastpay时必填
//            reqParamMap.put("fast_pay_id_no", ""); //证件号，当pay_mode为fastpay或fdfastpay时必填
//            reqParamMap.put("fast_pay_validity", ""); //有效期，当pay_mode为fastpay或fdfastpay时，且卡类型为信用卡时必填
//            reqParamMap.put("fast_pay_mobile", ""); //手机号,当pay_mode为fastpay时使用
//            reqParamMap.put("fast_pay_cvv2", ""); //安全码,当pay_mode为fastpay或fdfastpay时，且卡类型为信用卡时必填
//            reqParamMap.put("extend_params", ""); //业务扩展参数，一个json字符串
//            reqParamMap.put("business_code", ysepayConfig.getBusinessCode()); //业务代码
//            reqParamMap.put("extra_common_param", ""); //公用回传参数
//            reqParamMap.put("sub_merchant", ""); //二级商户信息
//            reqParamMap.put("consignee_info", ""); //收货人信息json格式
//            reqParamMap.put("appid", ""); //微信分配的子商户公众号账号ID

            JSONObject bizContentJSON = new JSONObject();
            bizContentJSON.put("out_trade_no", payOrder.getPayOrderId());
            bizContentJSON.put("subject", payOrder.getSubject());
            bizContentJSON.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getAmount() + ""));
            bizContentJSON.put("seller_id", ysepayConfig.getSellerId());
            bizContentJSON.put("seller_name", ysepayConfig.getSellerName());
            bizContentJSON.put("timeout_express","2h");
            bizContentJSON.put("business_code", ysepayConfig.getBusinessCode());
            bizContentJSON.put("bank_type", bankType);  //微信扫码支付1902000  支付宝：1903000

            //扫码支付 参数信息
            reqParamMap.put("biz_content", bizContentJSON.toJSONString());

            //获取配置私钥
            String privatePfxFilePath = payConfig.getCertRootPath() + File.separator + getChannelName() + File.separator + ysepayConfig.getPrivatePfxPath();

            //签名
            String signStr = SignUtils.rsaSign(reqParamMap, privatePfxFilePath, ysepayConfig.getPfxPwd());
            reqParamMap.put("sign", signStr); //RSA签名字符串，再用Base64编码

            //请求接口
            logger.info("ysepay req reqParamMap: {}", reqParamMap);
            String resStr = Https.httpsSend(YsepayConfig.API_URL, reqParamMap);
            logger.info("ysepay resData: {}", resStr);

            if(StringUtils.isEmpty(resStr)){
                throw new Exception("返回数据为null");
            }
            JSONObject resJSON = JSON.parseObject(resStr, Feature.OrderedField); //保持原始对象顺序

            String resSign = resJSON.getString("sign");  //返回数据的签名
            JSONObject resBizJSON = resJSON.getJSONObject("ysepay_online_qrcodepay_response");

            //银盛公钥文件
            String publicCerFilePath = payConfig.getCertRootPath() + File.separator + getChannelName() + File.separator + ysepayConfig.getPublicCerPath();

            boolean isTrue = SignUtils.rsaCheckContent(publicCerFilePath, resBizJSON.toJSONString(), resSign);
            if(!isTrue){
                throw new Exception("验签失败！");
            }

            JSONObject payInfo = new JSONObject();
            String codeUrl = resBizJSON.getString("source_qr_code_url"); // 二维码支付链接
            String codeImgUrl = resBizJSON.getString("qr_code_url");
            retObj.setQrInfo(codeUrl, codeImgUrl);
            int result = commonService.payOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
            logger.info("[{}]更新订单状态为支付中:payOrderId={},prepayId={},result={}", getChannelName(), payOrder.getPayOrderId(), "", result);
            return retObj;

        } catch (Exception e) {
            logger.error("ysepay error", e);
            return ApiBuilder.bizError("下单失败");
        }
    }
}
